const log4js = require('../utils/logUtils');
const logger = log4js.getLogger('web');
const settingModel = require("../model/setting");
const constants = require('../db/constants');
const fs = require('fs');
const request = require("request");
const config = require("../db/config");
const zlMediaKit = require("./ZlMediaKitApi");
const server = require("../sip/server/server");

const TAG = "[ZlMediaKitUtils]";

let inviteCache = {};

module.exports = {
    /**
     * TODO: 准备换成httpUtils
     * 调用zlmediakit 进行截图操作，暂时不用
     */
    snap0(query, deviceid, channel) {
        return new Promise(function (resolve) {
            let url = constants.zlmedia.url + 'index/api/getSnap';
            let param = "?" + query;
            let path = settingModel.cache.snap_path + "/" + deviceid + "_" + channel + ".jpg";
            request(url + param).pipe(fs.createWriteStream(path));
            resolve({});
        });
    },
    async startZlkRecord(camera){
        // 调用 ZlMediaKit
        const channel = camera.channel_id;
        const deviceid = camera.deviceid;
        let type;  //0:hls, 1:mp4
        if(camera.hasOwnProperty('type')){
            type = camera.type;
        }else{
            type = 1;
        }
        const vhost = '__defaultVhost__';
        const app = 'proxy';
        const stream = `${deviceid}_${channel}`;
        const customized_path = '';
        // 20分钟为最大录像时长
        const max_second = config.record.duration * 60;
        // 从数据库加载配置
        // 先确定play再录制
        await zlMediaKit.pull(app, stream, camera.mrl);
        const data = await zlMediaKit.startRecord(camera.server_id, type, vhost, app, stream, customized_path, max_second);
        logger.info(TAG, "调用ZlMediaKit录像返回:", data);
        camera.recording=true;
        camera.recordFilePath = data.msg;
    },
    async isZlkRecording(camera){
        // 调用 ZlMediaKit
        const channel = camera.channel_id;
        const deviceid = camera.deviceid;
        let type;  //0:hls, 1:mp4
        if(camera.hasOwnProperty('type')){
            type = camera.type;
        }else{
            type = 1;
        }
        const vhost = '__defaultVhost__';
        const app = 'proxy';
        const stream = `${deviceid}_${channel}`;
        const data = await zlMediaKit.isRecording(camera.server_id, type, vhost, app, stream);
        logger.info(TAG, "ZlMediaKit是否录像中?", data);
        return data.status;
    },
    async stopZlkRecord(camera){
        // 调用 ZlMediaKit
        const channel = camera.channel_id;
        const deviceid = camera.deviceid;
        let type;  //0:hls, 1:mp4
        if(camera.hasOwnProperty('type')){
            type = camera.type;
        }else{
            type = 1;
        }
        const vhost = '__defaultVhost__';
        const app = 'proxy';
        const stream = `${deviceid}_${channel}`;
        const data = await zlMediaKit.stopRecord(camera.server_id, type, vhost, app, stream);
        logger.info(TAG, "ZlMediaKit停止录像返回:", data);
        camera.recording=false;
        camera.recordFilePath = '';
    },
    /**
     *
     * @param stream_id
     * @param mediaServerId
     * @param deviceId
     * @param channelId
     * @param s Play 或 Playback
     * @param startTime 回放开始时间
     * @param endTime 回放结束时间
     * @return {Promise<{code: number, error: string}|{msg: string, code: number, error: string}>}
     */
    async play(stream_id, mediaServerId, deviceId, channelId, s, startTime, endTime){
        let error, code, msg;
        // 获取一个port
        try {
            const rtpRet = await zlMediaKit.openRtpServer({
                body: {
                    stream_id: stream_id,
                    mediaServerId: mediaServerId
                }
            });
            const res1 = rtpRet.res;
            const media_ip = rtpRet.media_ip;
            const intranet = rtpRet.intranet;
            let sendPort;
            if (res1.code === -300) {
                // 流已经存在，去查找一下
                const rows = await zlMediaKit.listRtpServer(mediaServerId);
                let port = 0;
                const rtpPorts = rows.data.find((item) => {
                    return item.stream_id === stream_id
                });
                logger.info(TAG, `[onPlay] mediaServerId=${mediaServerId} stream_id=${stream_id} 打开rtp端口时反馈流已存在,返回值:`,
                    res1, 'intranet=', intranet, 'listRtpServer列表', rows);
                if (rtpPorts) {
                    port = rtpPorts.port;
                }
                if (port > 0) {
                    sendPort = port;
                } else {
                    sendPort = null;
                    error = 'request rtp from zlMediaKit failure';
                    code = 1;
                    return {code, error};
                }
            } else {
                // 新流，需要分配新的端口
                logger.info(TAG, `[onPlay] mediaServerId=${mediaServerId} stream_id=${stream_id} 打开rtp端口，新流准备分新端口`, res1, media_ip);
                sendPort = res1.port;
            }
            if (sendPort) {
                // 针对同一个 deviceId, channelId ,除非sendPort发生变化 ，否则限制invite时间
                const key = `${deviceId}_${channelId}_${sendPort}`;
                const now = new Date().getTime();
                // 删除掉1分钟前的缓存
                Object.keys(inviteCache).forEach((item) => {
                    if (now - inviteCache[item] > 1000*5) {
                        delete inviteCache[item];
                    }
                });
                if (inviteCache[key]) {
                    logger.info(TAG, `[onPlay] mediaServerId=${mediaServerId} stream_id=${stream_id} 5秒内已经发过invite了，不再发送`);
                    code = 0;
                    msg = 'success';
                }else {
                    // 记录下这个流的信息
                    inviteCache[key] = now;
                    logger.info(TAG, '[onPlay] 记录缓存后', 'inviteCache', inviteCache);
                    const ret = await server.invite(media_ip, deviceId, channelId, sendPort, s, startTime, endTime);
                    logger.info(TAG, `[onPlay] mediaServerId=${mediaServerId} stream_id=${stream_id} port=${sendPort} 发送invite信令 返回值：`, ret);
                    if (ret) {
                        code = 0;
                        msg = 'success';
                    } else {
                        code = 1;
                        error = 'send gb28181 invite failure';
                    }
                }
            } else {
                logger.error(TAG, `[onPlay] mediaServerId=${mediaServerId} stream_id=${stream_id} 发送invite信令时没获取到rtp端口`);
                code = 0;
                msg = 'success';
            }
        } catch (e) {
            code = 1;
            error = e;
        }
        return {code, error, msg};
    }
};
